import browser from 'webextension-polyfill';
import { js_beautify as beautify } from 'js-beautify';
import UpgradeProject from './migrate';
import { verifyFile, FileTypes, migrateTestCase, migrateProject, migrateUrls } from './legacy/migrate';
import TestCase from '@/popup/models/TestCase';
import UiState from '@/popup/store/UiState';
import PlaybackState from '@/popup/store/PlaybackState';
import ModalState from '@/popup/store/ModalState';
import Selianize, { ParseError } from 'selianize';
import Manager from '@/popup/plugin/manager';
import chromeGetFile from './filesystem/chrome';
import firefoxGetFile from './filesystem/firefox';
import { userAgent as parsedUA } from '@/common/utils';
import { project as projectProcessor } from '@seleniumhq/side-utils';

export function getFile(path) {
    const browserName = parsedUA.browser.name;
    return (() => {
        if (browserName === 'Chrome') {
            return chromeGetFile(path);
        } else if (browserName === 'Firefox') {
            return firefoxGetFile(path);
        } else {
            return Promise.reject(new Error('Operation is not supported in this browser'));
        }
    })().then((blob) => {
        return new Promise((res) => {
            const reader = new FileReader();
            reader.addEventListener('load', () => {
                res(reader.result);
            });
            reader.readAsDataURL(blob);
        });
    });
}

export function loadAsText(blob) {
    return new Promise((res) => {
        const fileReader = new FileReader();
        fileReader.onload = (e) => {
            res(e.target.result);
        };

        fileReader.readAsText(blob);
    });
}

export function saveProject(_project) {
    const project = _project.toJS();
    downloadProject(project);
    UiState.saved();
}

function sendSaveProjectEvent(project) {
    const saveMessage = {
        action: 'event',
        event: 'saveProject',
        options: {
            project,
        },
    };
    browser.runtime.sendMessage(Manager.controller.id, saveMessage);
}

function downloadProject(project) {
    return exportProject(project).then((snapshot) => {
        if (snapshot) {
            project.snapshot = snapshot;
            Object.assign(project, Manager.emitDependencies());
        }
        if (UiState.isControlled) {
            //If in control mode, send the project in a message and skip downloading
            sendSaveProjectEvent(project);
        } else {
            browser.downloads.download({
                filename: projectProcessor.sanitizeProjectName(project.name) + '.side',
                url: createBlob('application/side', beautify(JSON.stringify(project), { indent_size: 2 })),
                saveAs: true,
                conflictAction: 'overwrite',
            });
        }
    });
}

function exportProject(project) {
    return Manager.validatePluginExport(project).then(() => {
        return Selianize(project, {
            silenceErrors: true,
            skipStdLibEmitting: true,
        }).catch((err) => {
            const markdown = ParseError((err && err.message) || err);
            ModalState.showAlert({
                title: 'Error saving project',
                description: markdown,
                confirmLabel: 'download log',
                cancelLabel: 'close',
            }).then((choseDownload) => {
                if (choseDownload) {
                    browser.downloads.download({
                        filename: project.name + '-logs.md',
                        url: createBlob('text/markdown', markdown),
                        saveAs: true,
                        conflictAction: 'overwrite',
                    });
                }
            });
            return Promise.reject();
        });
    });
}

export function downloadUniqueFile(filename, body, mimeType = 'text/plain') {
    browser.downloads.download({
        filename,
        url: createBlob(mimeType, body),
        saveAs: true,
        conflictAction: 'overwrite',
    });
}

let previousFile = null;
// eslint-disable-next-line
function createBlob(mimeType, data) {
    const blob = new Blob([data], {
        type: mimeType,
    });
    // If we are replacing a previously generated file we need to
    // manually revoke the object URL to avoid memory leaks.
    if (previousFile !== null) {
        window.URL.revokeObjectURL(previousFile);
    }
    previousFile = window.URL.createObjectURL(blob);
    return previousFile;
}

export function loadProject(project, file) {
    function displayError(error) {
        ModalState.showAlert({
            title: 'Error migrating project',
            description: error.message,
            confirmLabel: 'close',
        });
    }
    return loadAsText(file).then((contents) => {
        if (/\.side$/i.test(file.name)) {
            loadJSProject(project, UpgradeProject(JSON.parse(contents)));
        } else {
            try {
                const type = verifyFile(contents);
                if (type === FileTypes.Suite) {
                    ModalState.importSuite(contents, (files) => {
                        try {
                            loadJSProject(project, migrateProject(files));
                        } catch (error) {
                            displayError(error);
                        }
                    });
                } else if (type === FileTypes.TestCase) {
                    let { test, baseUrl } = migrateTestCase(contents);
                    if (project.urls.length && !project.urls.includes(baseUrl)) {
                        ModalState.showAlert({
                            title: 'Migrate test case',
                            description: `The test case you're trying to migrate has a different base URL (${baseUrl}) than the project's one.  \nIn order to migrate the test case URLs will be made absolute.`,
                            confirmLabel: 'migrate',
                            cancelLabel: 'discard',
                        }).then((choseMigration) => {
                            if (choseMigration) {
                                UiState.selectTest(project.addTestCase(TestCase.fromJS(migrateUrls(test, baseUrl))));
                            }
                        });
                    } else {
                        UiState.selectTest(project.addTestCase(TestCase.fromJS(test, baseUrl)));
                    }
                }
            } catch (error) {
                displayError(error);
            }
        }
    });
}

// 加载项目
export function loadJSProject(project, data) {
    UiState.changeView('Tests');
    PlaybackState.clearPlayingCache();
    UiState.clearViewCache();
    project.fromJS(data);
    UiState.projectChanged();
    Manager.emitMessage({
        action: 'event',
        event: 'projectLoaded',
        options: {
            projectName: project.name,
            projectId: project.id,
        },
    });
}
